package com.example.synchronizedLearning;

/**
 * 对象锁（this）是对象级别的锁
 * 线程在调用某个对象的 synchronized 实例方法或 synchronized(this) 代码块时，
 * 必须首先获得该对象的锁（即当前对象的 Monitor）。
 * 持有对象锁期间，其他线程无法访问同一对象中的其他 synchronized 方法或 synchronized(this) 代码块
 * 即使是不同的 synchronized 方法，也会被阻塞。
 * 但其他线程可以访问当前对象中的非 synchronized 方法。
 * 对象锁是针对对象级别的，不同对象实例之间的 synchronized 方法是互不干扰的
 * 不同对象有各自的对象锁。
 */
public class Syn5 {
    public void print() {
        /**
         * synchronized(this) 表示锁住当前对象，其中的**"当前对象"指的是当前实例对象**，即正在执行该方法或代码块的对象。
         *
         * 在 Java 中，每个对象在内存中都有唯一的实例（通过 new 关键字创建）。
         * this 代表当前对象的引用，指向当前对象实例在堆（Heap）中的内存地址。
         * 在实例方法中，this 表示当前对象实例。
         */
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " - " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

class Syn5Test {
    public static void main(String[] args) {

        Syn5 obj = new Syn5();

        Thread t1 = new Thread(obj::print);
        Thread t2 = new Thread(obj::print);

        /**
         * obj.print() 在两个线程中执行。
         * synchronized(this) 代表锁住的是对象 obj（即当前实例）。
         * 线程 t1 执行 print() 方法时，获得对象锁 obj。
         * 线程 t2 必须等待 t1 释放 obj 的锁后才能继续执行。
         */

        t1.start();
        t2.start();

        /**
         * 每个对象实例有自己的对象锁。
         * 不同对象的 synchronized(this) 是互不影响的。
         */
        Syn5 obj1 = new Syn5();
        Syn5 obj2 = new Syn5();

        Thread t_obj1 = new Thread(obj1::print);
        Thread t_obj2 = new Thread(obj2::print);

        /**
         * obj1 和 obj2 是不同的对象。
         * synchronized(this) 只在对象级别上生效。
         * 线程 t1 锁住 obj1，线程 t2 锁住 obj2。
         * 由于是不同对象的锁，因此 t1 和 t2 不会互相干扰。
         */
        t_obj1.start();
        t_obj2.start();

    }
}
